﻿using AnyLink.Domain.Options;
using AnyLink.Infrastructure.Auth;
using AnyLink.Infrastructure.Cache;
using AnyLink.Infrastructure.Converter;
using AnyLink.Infrastructure.Filters;
using AnyLink.Infrastructure.Services;
using AnyLink.Infrastructure.Utils;
using AspNetCoreRateLimit;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Text.Encodings.Web;
using System.Text.Json.Serialization;
using System.Text.Unicode;

namespace AnyLink.Infrastructure
{
    /// <summary>
    /// 全局变量
    /// </summary>
    public class Global
    {
        /// <summary>
        /// 应用服务
        /// </summary>
        public static IServiceCollection InternalServices;
        /// <summary>
        /// 根服务
        /// </summary>
        public static IServiceProvider RootServices;
        /// <summary>
        /// 全局配置选项
        /// </summary>
        public static IConfiguration Configuration;// => new ConfigurationBuilder().Build();

        /// <summary>
        /// 配置应用启动
        /// </summary>
        /// <param name="builder"></param>
        public static void ConfigureApplication(IHostApplicationBuilder builder)
        {
            // 获取程序执行目录
            //var executeDirectory = AppContext.BaseDirectory;
            //var jsonFilePath = Path.Combine(executeDirectory, "appsettings.json");

            builder.Configuration.AddJsonFile("appsettings.json",optional: true, reloadOnChange: true);
            Configuration=builder.Configuration;

            builder.Services.AddSingleton(e => GetConfig<DbConnectionOptions>());
            builder.Services.AddSingleton(e => GetConfig<JwtOptions>());
            //builder.Services.AddOptions().Configure<JwtOptions>(e => Configuration.GetSection("Jwt").Bind(e));
            //builder.Services.AddOptions().Configure<DbConnectionOptions>(e => Configuration.GetSection("DbConnection").Bind(e));

            builder.Services.AddMemoryCache();
            builder.Services.AddSingleton<ICache, MemoryCacheHelper>();
            builder.Services.AddSqlSugar();
            builder.Services.AddAuth();
            builder.Services.AddService();
            #region 注入http上下文
            //builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            builder.Services.AddHttpContextAccessor();
            #endregion
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();            
            builder.Services.AddControllers();
            #region 允许服务器同步IO
            builder.Services.Configure<KestrelServerOptions>(a => a.AllowSynchronousIO = true)
                            .Configure<IISServerOptions>(a => a.AllowSynchronousIO = true);
            #endregion

            #region 添加IP限流
            builder.Services.Configure<IpRateLimitOptions>(a => a = GetConfig<IpRateLimitOptions>("IpRateLimiting"));
            builder.Services.Configure<IpRateLimitPolicies>(a => a = GetConfig<IpRateLimitPolicies>("IpRateLimitPolicies"));
            builder.Services.AddInMemoryRateLimiting();
            builder.Services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
            #endregion

            builder.Services.AddControllersWithViews(options =>
            {
                //options.Filters.Add<LogActionFilter>();
                options.Filters.Add<GlobalExceptionFilter>();
            }).AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
                options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
                options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
                options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
            });

            InternalServices = builder.Services;
            RootServices = builder.Services.BuildServiceProvider();            
        }

        /// <summary>
        /// 获取服务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetService<T>()
        {
            return RootServices.GetService<T>();
        }
        /// <summary>
        /// 获取服务
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T GetRequiredService<T>()
        {
            return RootServices.GetRequiredService<T>();
        }

        public static TOptions GetConfig<TOptions>(TOptions defaultValue = default)
        {
            string path = typeof(TOptions).Name;
            if (path.EndsWith("Options"))
            {
                path = path.Substring(0, path.Length - 7);
                //path = path.PadLeft(path.Length - 7);
            }
            try
            {  
                return Configuration.GetSection(path).Get<TOptions>();
            }
            catch (Exception)
            {
                if (defaultValue != null) return defaultValue;

                throw new Exception("配置（" + path + "）不存在");//, "配置不存在");
            }
        }


        /// <summary>
        /// 获取配置
        /// </summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <param name="path">配置中对应的Key</param>
        /// <returns>TOptions</returns>
        public static TOptions GetConfig<TOptions>(string path, TOptions defaultValue = default)
        {
            try
            {
                return Configuration.GetSection(path).Get<TOptions>();
            }
            catch (Exception)
            {
                if (defaultValue != null) return defaultValue;

                throw new Exception("配置（" + path + "）不存在");//, "配置不存在");
            }
        }
        /// <summary>
        /// 获取配置值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetConfigValue(string key,string defaultValue = "")
        {
            try
            {
                if (key.IsNull()) return defaultValue;
                return Configuration[key];
            }
            catch
            {
                return defaultValue;
            }
        }
    }
}
